package com.pig4cloud.pigx.auth.handler;

import com.pig4cloud.pigx.common.security.constant.CacheConstants;
import com.pig4cloud.pigx.common.security.handler.AuthenticationFailureHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @Author 兔子不吃窝边曹
 * @create 2022/8/5 9:29
 **/
@Slf4j
@Component
@AllArgsConstructor
public class PigxAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler {

    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 密码错误自动锁定用户
     *
     * @param authenticationException 错误信息
     * @param authentication          认证信息
     * @param request                 请求信息
     * @param response                响应信息
     */
    @Async
    @Override
    public void handle(AuthenticationException authenticationException, Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        // 只处理账号密码错误异常 注意这里除了用户名和密码错误以外，还有客户端的clientId和clientSecret错误
        if (!(authenticationException instanceof BadCredentialsException)) {
            return;
        }


        String username = authentication.getName();
        String key = String.format("%s:%s", CacheConstants.LOGIN_ERROR_TIMES, username);
        // 通过数据库查询密码错误的次数和自动过期时间
        // 演示写直接写死测试
        Long deltaTimes = 5L;
        Long times = redisTemplate.opsForValue().increment(key);
        Long deltaTime = 1L;
        redisTemplate.expire(key, deltaTime, TimeUnit.HOURS);

        // 超过5次锁定
        if (deltaTimes <= times) {
            // 调用接口将用户锁起来
            log.info("用户登录5次失败：{}", username);
        }

    }
}
